#pragma once
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

const string gpath = "/home/yjl/Code/lesson2/sharememory";
const int gprojId = 0x6666;
const int gshmsize = 4096; // 建议申请4096（4KB）的整数倍
mode_t gmode = 0600;

string ToHex(key_t k)
{
    char buff[64];
    snprintf(buff, sizeof(buff), "0x%x", k);
    return buff;
}

class ShareMemory
{
private:
    void CreateShmHelper(int shmflg)
    {
        // 1.创建key
        _key = ::ftok(gpath.c_str(), gprojId);
        if (_key < 0)
        {
            cerr << "ftok error" << endl;
        }
        cout << "key: " << ToHex(_key) << endl;
        // 2.创建共享内存 && 获取
        _shmid = ::shmget(_key, gshmsize, shmflg);
        if (_shmid < 0)
        {
            cerr << "shmget error" << endl;
        }
        cout << "shmid: " << _shmid << endl;
    }

public:
    ShareMemory()
        : _shmid(-1), _key(0), _addr(nullptr)
    {
    }
    ~ShareMemory() {}

    void CreateShm()
    {
        if (_shmid == -1)
            this->CreateShmHelper(IPC_CREAT | IPC_EXCL | gmode);
    }
    void GetShm()
    {
        CreateShmHelper(IPC_CREAT);
    }
    void AttachShm()
    {
        // 3.挂接
        _addr = ::shmat(_shmid, nullptr, 0); // 若不给权限会挂接失败
        if ((long long)_addr == -1)
        {
            cout << "attach error" << endl;
        }
    }
    void DetachShm()
    { // 4.去挂接
        if (_addr != nullptr)
        {
            ::shmdt(_addr);
            cout << "detach success " << endl;
        }
    }
    void DeleteShm()
    {
        // 5.释放内存
        ::shmctl(_shmid, IPC_RMID, nullptr);
    }
    void ShmMeta()
    {
        // 获取属性
        struct shmid_ds buffer; // 系统提供的数据类型
        int n = ::shmctl(_shmid, IPC_STAT, &buffer);
        if (n < 0)
        {
            return;
        }
        cout<<"#############################"<<endl;
        cout << buffer.shm_atime << endl;
        cout << buffer.shm_cpid << endl;
        cout << buffer.shm_ctime << endl;
        cout << buffer.shm_nattch << endl;
        cout << ToHex(buffer.shm_perm.__key) << endl;
        cout<<"#############################"<<endl;

    }
    void *GetAddr()
    {
        return _addr;
    }

private:
    key_t _key;
    int _shmid;
    void *_addr;
};

ShareMemory shm;